package com.woniuxy.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.common.enums.RedisConstant;
import com.woniuxy.common.result.Result;
import com.woniuxy.common.result.enums.IErrorCode;
import com.woniuxy.common.result.enums.impl.BusinessCode;
import com.woniuxy.common.utils.JwtUtils;
import com.woniuxy.gateway.config.IgnorePathConfig;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@Slf4j
public class AuthFilter implements GlobalFilter {
    @Autowired
    JwtUtils jwtUtils;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    IgnorePathConfig ignorePathConfig;

    @Override
    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1. 放行不需要认证的资源  /user/login  /user/register  白名单资源
        //  获取request对象  和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 1.1 、获取这些白名单的资源的路径
        String path = request.getURI().getPath();
        log.info("接受请求的路径:{}",path);
        //获取所有需要放行的资源路径
        PathMatcher pathMatcher = new AntPathMatcher();
        List<String> uris = ignorePathConfig.getUris();
        for (String uri : uris) {
            if(pathMatcher.match(uri,path)){
                //放行
                return chain.filter(exchange);
            }
        }
        //2 拦截其余路径，获取请求头中的 token
        //token = token.replace("Bearer ",""); //去掉token中前缀,可以不加
        String token = request.getHeaders().getFirst("token");
        //2.1 、token 为空
        //Assert.error(token, BusinessCode.TOKEN_ISNULL);过滤器中无法处理异常
        if (StringUtils.isEmpty(token)) {
            return  errorResponse(response, BusinessCode.TOKEN_ISNULL);
        }

        //2.1 、不为空则验证token是否合法
        boolean verifyToken = jwtUtils.verifyToken(token);
        if(!verifyToken){
            return errorResponse(response,BusinessCode.TOKEN_INVALID);
        }
        //获取 token中信息
        String id = jwtUtils.parseToken(token, "id")+"";

        //验证是否过期
        /*String redisToken = stringRedisTemplate.opsForValue().get(RedisConstant.USER_TOKEN + userId);
        if (StringUtils.isEmpty(redisToken)) {
            return errorResponse(response,BusinessCode.TOKEN_EXPIRATION);
        }*/
        String key = RedisConstant.USER_TOKEN+id;
        if(!stringRedisTemplate.hasKey(key)){
            return errorResponse(response,BusinessCode.TOKEN_EXPIRATION);
        }

        // token的续期  向redis中存储 token 恢复30分钟
        stringRedisTemplate.opsForValue().set(key,token,30, TimeUnit.MINUTES);

        //重写请求头 把 token 直接写到请求头
        request.mutate().header("token",token);

        return chain.filter(exchange);
    }
    private static Mono<Void> errorResponse(ServerHttpResponse response, IErrorCode errorCode) throws Exception {
        Result result = Result.fail(errorCode);
        byte[] bytes = new ObjectMapper().writeValueAsBytes(result);
        DataBuffer dataBuffer= response.bufferFactory().wrap(bytes);
        // 返回错误
        return response.writeWith(Mono.just(dataBuffer));
    }
}
